import dbus.service
import serial

bus = dbus.SessionBus("sim-client")

def splitDBusURI(serviceURI):
        busName = serviceURI[5:serviceURI.find('/')]
        servicePath = serviceURI[serviceURI.find('/'):]
        return (busName,  servicePath)

class Driver:

    def setDevicePath(self, path):
        self.__path = path

    def setDeviceId(self, id):
        self.__id = id

    def getDevicePath(self):
        return self.__path

    def getDeviceId(self):
        return self.__id

class GPSDriver(Driver):
    
    def __init__(self,  devicePath,  deviceId):
        self.setDevicePath(devicePath)
        self.setDeviceId(deviceId)
        if devicePath.find(':') > -1:
            self.__dev = self.getDevicePath().split(':')[0]
            self.__br = self.getDevicePath().split(':')[1]
            self.__ser = serial.Serial(self.__dev, self.__br, timeout=0.5)
        else:
            self.__ser = open(devicePath,  'r')
        
    def readlines(self):
        lines = []
        for x in range(10):
            lines.append(self.__ser.readline())
        return lines
        
    # returns - (lat, lon, alt, speed, dir, time - (HH, MM, SS, MS), date(YY, MM, DD), status1, status2)
    def getLocation(self):
        lines = self.readlines()
        gprmc = None
        gpgga = None
        l1 = False 
        l2 = False
        for line in lines:
            if line.startswith("$GPRMC"):
                gprmc = line
            if line.startswith("$GPGGA"):
                gpgga = line
            if (not gprmc is None) and (not gpgga is None):
                break                
        if not gprmc is None:
            l1 = True
        if not gpgga is None:
            l2 = True
        data = self.__parseData(gprmc,  gpgga)
        return (data[0], data[1], data[2], data[3], data[4], data[5], data[6], l1,  l2)
        
    def __parseData(self,  gprmc,  gpgga):
        if gprmc is None:
            return (-1,  -1,  -1,  -1,  -1,  (-1,  -1,  -1,  -1),  (-1,  -1,  -1))
        words1 = gprmc.split(",")
        if words1[2] == 'V':
            return (-1,  -1,  -1,  -1,  -1,  (-1,  -1,  -1,  -1),  (-1,  -1,  -1))
            
        time = (int(words1[1][0:2]),  int(words1[1][2:4]),  int(words1[1][4:6]),  int(words1[1][7:10]))
        lat = int(words1[3][0:2]) + float(words1[3][2:6]) / 60.0
        if words1[4] == 'S':
            lat = -lat
        lon = int(words1[5][0:3]) + float(words1[5][3:7]) / 60.0
        if words1[6] == 'W':
            lon = -lon
        speed = float(words1[7]) * 0.514 # ms-1
        dir = float(words1[8]) 
        date = (int(words1[9][4:6]) + 2000, int(words1[9][2:4]),  int(words1[9][0:2]))
        alt = -1
        if not gpgga is None:
            words2 = gpgga.split(",")
            if not words2[6] == "0":
                alt = float(words2[9])
            
        return (lat,  lon,  alt,  speed,  dir,  time,  date)

class SonarDriver(Driver):
    
    def __init__(self,  devicePath,  deviceId):
        self.setDevicePath(devicePath)
        self.setDeviceId(deviceId)
    
    def getDistance(self):
        return 5

class CompassDriver(Driver):
    
    def __init__(self,  devicePath,  deviceId):
        self.setDevicePath(devicePath)
        self.setDeviceId(deviceId)
    
    def getDirection(self):
        return 0.0

class MetalDetectorDriver(Driver):
    
    def __init__(self,  devicePath,  deviceId):
        self.setDevicePath(devicePath)
        self.setDeviceId(deviceId)
    
    def getMines(self):
        return ()

class NavigationDriver(Driver):
    
    def __init__(self,  devicePath,  deviceId):
        self.setDevicePath(devicePath)
        self.setDeviceId(deviceId)
    
    def moveUp(self):
        pass

    def moveDown(self):
        pass
    
    def moveLeft(self):
        pass
    
    def moveRight(self):
        pass
    
    def setSpeed(self, speed):
        pass
    
    def stop(self):
        pass

class GPSDriverSim(Driver):
    
    def __init__(self,  devicePath,  deviceId):
        self.setDevicePath(devicePath)
        self.setDeviceId(deviceId)
        (busName,  objectPath) = splitDBusURI(self.getDevicePath())
        service = bus.get_object(busName, objectPath)
        self.__getLocationRemote = service.get_dbus_method('getLocation')
    
    def getLocation(self):
        return self.__getLocationRemote()

class SonarDriverSim(Driver):
    
    def __init__(self,  devicePath,  deviceId):
        self.setDevicePath(devicePath)
        self.setDeviceId(deviceId)
        (busName,  objectPath) = splitDBusURI(self.getDevicePath())
        service = bus.get_object(busName, objectPath)
        self.__getDistanceRemote = service.get_dbus_method('getDistance')
    
    def getDistance(self):
        return self.__getDistanceRemote()

class CompassDriverSim(Driver):
    
    def __init__(self,  devicePath,  deviceId):
        self.setDevicePath(devicePath)
        self.setDeviceId(deviceId)
        (busName,  objectPath) = splitDBusURI(self.getDevicePath())
        service = bus.get_object(busName, objectPath)
        self.__getDirectionRemote = service.get_dbus_method('getDirection')
    
    def getDirection(self):
        return self.__getDirectionRemote()

class MetalDetectorDriverSim(Driver):
    
    def __init__(self,  devicePath,  deviceId):
        self.setDevicePath(devicePath)
        self.setDeviceId(deviceId)
        (busName,  objectPath) = splitDBusURI(self.getDevicePath())
        service = bus.get_object(busName, objectPath)
        self.__getMinesRemote = service.get_dbus_method('getMines')
    
    def getMines(self):
        return self.__getMinesRemote()

class NavigationDriverSim(Driver):
    
    def __init__(self,  devicePath,  deviceId):
        self.setDevicePath(devicePath)
        self.setDeviceId(deviceId)
        (busName,  objectPath) = splitDBusURI(self.getDevicePath())
        service = bus.get_object(busName, objectPath)
        self.__moveUpRemote = service.get_dbus_method('moveUp')
        self.__moveDownRemote = service.get_dbus_method('moveDown')
        self.__moveLeftRemote = service.get_dbus_method('moveLeft')
        self.__moveRightRemote = service.get_dbus_method('moveRight')
        self.__setSpeedRemote = service.get_dbus_method('setSpeed')
        self.__stopRemote = service.get_dbus_method('stop')
    
    def moveUp(self):
        self.__moveUpRemote()

    def moveDown(self):
        self.__moveDownRemote()
    
    def moveLeft(self):
        self.__moveLeftRemote()
    
    def moveRight(self):
        self.__moveRightRemote()
    
    def setSpeed(self, speed):
        self.__setSpeedRemote(speed)
    
    def stop(self):
        self.__stopRemote()
